package genetic.core;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

/**
 * This class represents a population of {@link Individual}s.
 * 
 * @author vasek
 *
 */
public class Population implements List<Individual> {
	
	private LinkedList<Individual> population;
	private Selection selectionPolicy;
	
	/**
	 * Constructor. Initial population is created based on prototype individual.
	 * 
	 * @param size size of the population
	 * @param prototype prototype to create initial population
	 * @param selection selection policy
	 */
	public Population(int size, Individual prototype, Selection selection) {
		this.selectionPolicy = selection;
		this.population = new LinkedList<Individual>();
		for (int i = 0; i < size; i++) {
			population.add(prototype.clone());
		}
	}
	
	/**
	 * @return best {@link Individual} from population.
	 */
	public Individual getBest() {
		Individual best = population.getFirst();
		
		for (Individual individual : population) {
			if (individual.getFitness() >= best.getFitness()) {
				best = individual;
			}
		}
		
		return best;
    }

	/**
	 * Evolves this population to next generation.
	 */
	public void nextGeneration() {
		final LinkedList<Individual> breed = new LinkedList<Individual>();
		final int reproductions = (population.size() - GeneticAlgorithmConstants.ELITISM); 
		
		for (int i = 0; i < reproductions; i++) {
            final Individual reproduce = selectionPolicy.reproduce(population);
            breed.add(reproduce);
		}
		
		for (int i = 0; i < GeneticAlgorithmConstants.ELITISM; i++) {
			final Individual elite = population.get(i);
			breed.add(elite);
		}

		population = breed;
		Collections.sort(population);
	}

    @Override
    public int size() {
        return population.size();    
    }

    @Override
    public boolean isEmpty() {
        return population.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return population.contains(o);
    }

    @Override
    public Iterator<Individual> iterator() {
        return population.iterator();
    }

    @Override
    public Object[] toArray() {
        return population.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return population.toArray(a);
    }

    @Override
    public boolean add(Individual individual) {
        return population.add(individual);
    }

    @Override
    public boolean remove(Object o) {
        return population.remove(o);
    }
                                  
    @Override
    public boolean containsAll(Collection<?> c) {
        return population.containsAll(c);
    }

    @Override
    public boolean addAll(Collection<? extends Individual> c) {
        return population.addAll(c);
    }

    @Override
    public boolean addAll(int index, Collection<? extends Individual> c) {
        return population.addAll(index, c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return population.removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return population.retainAll(c);
    }

    @Override
    public void clear() {
        population.clear();
    }

    @Override
    public Individual get(int index) {
        return population.get(index);
    }

    @Override
    public Individual set(int index, Individual element) {
        return population.set(index, element);
    }

    @Override
    public void add(int index, Individual element) {
        population.add(index, element);
    }

    @Override
    public Individual remove(int index) {
        return population.remove(index);
    }

    @Override
    public int indexOf(Object o) {
        return population.indexOf(o);
    }

    @Override
    public int lastIndexOf(Object o) {
        return population.lastIndexOf(o);
    }

    @Override
    public ListIterator<Individual> listIterator() {
        return population.listIterator();
    }

    @Override
    public ListIterator<Individual> listIterator(int index) {
        return population.listIterator(index);
    }

    @Override
    public List<Individual> subList(int fromIndex, int toIndex) {
        return population.subList(fromIndex, toIndex);
    }
}
